import hashlib
import pyaes
import blowfish
import binascii
from urllib.request import urlopen

from utils import BLOWFISH_SECRET, ARTIST_PICTURES_URL
from artist import DeezerArtist
from track_quality import DeezerTrackQuality

class DeezerTrack:
  def __init__(self, raw_data):
    song_data = raw_data["results"]["DATA"]
    self.title = song_data["SNG_TITLE"]
    self.song_id = song_data["SNG_ID"]
    self.artists = list(map(
      lambda a: DeezerArtist(
        artist_id = a["ART_ID"],
        name = a["ART_NAME"],
        picture_url = ARTIST_PICTURES_URL % a["ART_PICTURE"]
      ),
      song_data["ARTISTS"]
    ))
    self.md5_origin = song_data["MD5_ORIGIN"]
    self.media_version = song_data["MEDIA_VERSION"]
    self.qualities = DeezerTrackQuality.from_raw_data(song_data)
  def download(self, to_file = None, quality = None):
    if to_file == None:
      to_file = ', '.join(
        map(lambda a: a.name, self.artists)
      ) + ' - ' + self.title
    if quality == None:
      quality = self.qualities[len(self.qualities) - 1]
    file_format = DeezerTrackQuality.get_file_format(quality)
    file_name = to_file + file_format

    print('downloading to %s' % to_file)

    # get track url
    #  - step 1: put a bunch of info together and hash it
    step1 = b'\xa4'.join(map(
      lambda s: s.encode(), [
        self.md5_origin,
        file_format,
        str(self.song_id),
        self.media_version
      ]
    ))
    hash = hashlib.new("md5")
    hash.update(step1)
    step1_hash = hash.hexdigest()

    #  - step 2: hash + info + add padding
    step2 = str.encode(step1_hash) + b'\xa4' + step1 + b'\xa4'
    while len(step2) % 16 > 0:
      step2 += b'.'

    #  - step 3: AES encryption to get url
    # it will encrypt in parts of 16
    step3 = b''
    aes = pyaes.AESModeOfOperationECB(b'jo6aey6haid2Teih')
    for index in range(int(len(step2) / 16)):
      block = step2[(index * 16):(index * 16) + 16]
      step3 += binascii.hexlify(aes.encrypt(block))

    #  - step 4: make url
    url = "http://e-cdn-proxy-{}.deezer.com/mobile/1/{}".format(
      self.md5_origin[0], # first char of md5origin is cdn to use
      step3.decode('utf-8')
    )

    # get blowfish key
    hash = hashlib.new("md5")
    hash.update(str(self.song_id).encode())
    hash = hash.hexdigest()
    key = ""
    for i in range(16):
      key += chr(ord(hash[i]) ^ ord(hash[i+16]) ^ ord(BLOWFISH_SECRET[i]))

    # download and decrypt track
    with open(file_name, 'wb') as stream:
      response = urlopen(url)
      cipher = blowfish.Cipher(key.encode())
      length = int(response.getheader('Content-Length'))
      i = 0
      while True:
        chunk = response.read(2048)
        if not chunk:
          break
        if (i % 3) == 0 and len(chunk) == 2048:
          chunk = b"".join(
            cipher.decrypt_cbc(chunk, b"\x00\x01\x02\x03\x04\x05\x06\x07")
          )
        stream.write(chunk)
        i += 1
